package com.hncc.kumao.tool;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.Charset;

import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import com.hncc.kumao.entity.BreakpointUploadTask;
import com.hncc.kumao.entity.NetdiskAccessToken;
import com.hncc.kumao.entity.OfflineDownloadTask;
import com.hncc.kumao.exception.KumaoException;
import com.hncc.kumao.exception.KumaoNetdiskFileNotFoundException;
import com.hncc.kumao.util.ConstValue;
import com.hncc.kumao.util.EncodeUtils;
import com.hncc.kumao.util.MyDownloadProgress;
import com.hncc.kumao.util.MyFileUtils;
import com.hncc.kumao.util.MyHttpClientUtils;
import com.hncc.kumao.util.OfflineDownloadUtils;

/**
 * 操作Seafile的工具类
 * @author chen
 *
 */
public class SeafileOperation {

    private static String taskId;
    
    /**
     * 检查当前网盘信息是否有效
     * @param netdiskAccessToken 网盘信息
     * @return
     */
    public static boolean check(NetdiskAccessToken netdiskAccessToken) {
        String checkUrl = netdiskAccessToken.getNetdiskUrl() + "/api2/account/info/";
        String responseContent = "";
        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        try {
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(10000)
                    .setConnectionRequestTimeout(10000)
                    .setSocketTimeout(10000)
                    .build();
            HttpGet httpGet = new HttpGet(checkUrl);
            httpGet.setConfig(requestConfig);
            httpGet.addHeader("Authorization", "Token " + netdiskAccessToken.getAccessToken());
            httpGet.addHeader("Accept", "application/json; charset=utf-8; indent=4");
            response = httpclient.execute(httpGet);
            //System.out.println(response.getStatusLine());
            int statusCode = response.getStatusLine().getStatusCode();
            HttpEntity entity = response.getEntity();  
            responseContent = MyHttpClientUtils.getResponseString(entity);
            //System.out.println("debug:" + responseContent);  
            EntityUtils.consume(entity);
            if(statusCode == 200) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {  
            e.printStackTrace();
            return false;
        } finally {  
            try {
                if(response != null) {
                    response.close();
                }
                httpclient.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }
    
    //进行下载
    public static void download(OfflineDownloadTask offlineDownloadTask, 
            NetdiskAccessToken netdiskAccessToken, final MyDownloadProgress progress) throws Exception {
        try {
            taskId = offlineDownloadTask.getId();
            //获取库id,文件路径和文件名
            String fileUri = offlineDownloadTask.getFileUri();
            String libraryId = getLibraryId(fileUri);
            String filePath = getFilePath(fileUri);
            String encodeFilePath = EncodeUtils.encodePath(filePath, "UTF-8");
            //获取下载连接
            String getDownloadUrl = netdiskAccessToken.getNetdiskUrl() + "/api2/repos/" + 
                    libraryId + "/file/?p=" + encodeFilePath;
            String downloadUrl = getDownloadUrl(getDownloadUrl, netdiskAccessToken.getAccessToken());
            System.out.println(downloadUrl);
            //执行下载
            doDownload(downloadUrl, offlineDownloadTask.getFileSavePath(), new MyDownloadProgress() {
                @Override
                public void onProgress(Long currentSize, Long totalSize) {
                    progress.onProgress(currentSize, totalSize);
                }
            });
        } catch (Exception e) {
            //e.printStackTrace();
            throw e;
        }
    }
    
    //获取下载链接
    private static String getDownloadUrl(String url, String token) throws Exception {
        String responseContent = null;  
        CloseableHttpClient httpclient = HttpClients.createDefault();  
        CloseableHttpResponse response = null;
        String downloadUrl = null;
        try {
            HttpGet httpGet = new HttpGet(url); 
            httpGet.addHeader("Authorization", "Token " + token);
            httpGet.addHeader("Accept", "application/json; charset=utf-8; indent=4");
            response = httpclient.execute(httpGet);
            System.out.println(response.getStatusLine());
            int statusCode = response.getStatusLine().getStatusCode();
            if(statusCode != 200) {
                System.out.println("未找到该文件");
                throw new KumaoNetdiskFileNotFoundException("未找到该文件");
            }
            HttpEntity entity = response.getEntity();
            responseContent = MyHttpClientUtils.getResponseString(entity);
            System.out.println("debug:" + responseContent);  
            EntityUtils.consume(entity);  
            //处理一下字符串
            downloadUrl = responseContent.substring(1, responseContent.length() - 1);
        } catch (Exception e) {
            //e.printStackTrace();
            throw e;
        } finally {
            if(response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                }
            }
            if(httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                }  
            }
        }
        return downloadUrl;
    }
    
    //具体执行下载的方法
    private static void doDownload(String downloadUrl, String fileSavePath, MyDownloadProgress progress) throws Exception {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            HttpGet httpGet = new HttpGet(downloadUrl);
            response = httpclient.execute(httpGet);  
            System.out.println(response.getStatusLine());  
            HttpEntity httpEntity = response.getEntity();  
            long contentLength = httpEntity.getContentLength();
            //获取输入流
            is = httpEntity.getContent();
            //创建文件输出流
            if(OfflineDownloadUtils.getTaskProgressState(taskId) == ConstValue.OD_TASK_STATE_GOING) {
                //先创建文件夹，防止文件夹不存在报错
                File tempFile = new File(fileSavePath);
                if(!tempFile.exists()) {
                    if(!tempFile.getParentFile().exists()) {
                        tempFile.getParentFile().mkdirs();
                    }
                }
                fos = new FileOutputStream(fileSavePath);  
            }
            byte[] buffer = new byte[4096];  
            int r = 0;
            long totalRead = 0;
            if(fos != null) {
                while (((r = is.read(buffer)) > 0)) {
                    if(OfflineDownloadUtils.getTaskProgressState(taskId) != ConstValue.OD_TASK_STATE_GOING) {
                        break;
                    }
                    fos.write(buffer, 0, r);
                    totalRead += r;
                    if (progress != null) {
                        progress.onProgress(totalRead, contentLength);  
                    }  
                }
            }
            EntityUtils.consume(httpEntity);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            if(is != null) {
                is.close();
            }
            if(fos != null) {
                fos.close();
            }
            if(response != null) {
                response.close();
            }
            if(httpclient != null) {
                httpclient.close();
            }
        }
    }
    
    //上传
    public static void upload(BreakpointUploadTask breakpointUploadTask, NetdiskAccessToken netdiskAccessToken) throws Exception {
        try {
            //获取库id,文件路径和文件名
            String fileUri = breakpointUploadTask.getFileUri();
            String libraryId = getLibraryId(fileUri);
            String filePath = getFilePath(fileUri);
            String parentFilePath = filePath.substring(0, filePath.lastIndexOf("/"));
            String encodeFilePath = EncodeUtils.encodePath(parentFilePath, "UTF-8");
            
            //获取上传链接
            String getUploadUrl = netdiskAccessToken.getNetdiskUrl() + "/api2/repos/" + 
                    libraryId + "/upload-link/";
            String uploadUrl = getUploadUrl(getUploadUrl, netdiskAccessToken.getAccessToken());
            System.out.println(uploadUrl);
            
            //进行上传
            CloseableHttpClient httpclient = null;
            CloseableHttpResponse response = null;
            try {
                httpclient = HttpClients.createDefault();  
                HttpPost httpPost = new HttpPost(uploadUrl);
                //httpPost.addHeader("Content-type", "multipart/form-data; charset=utf-8");
                httpPost.addHeader("Authorization", "Token " + netdiskAccessToken.getAccessToken());
                MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                        .setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
                
                //要上传的文件
                File uploadFile = new File(breakpointUploadTask.getFileServerPath());
                
                //添加参数
                multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
                multipartEntityBuilder.addBinaryBody("file", uploadFile);
                //multipartEntityBuilder.addTextBody("parent_dir", parentFilePath);
                multipartEntityBuilder.addPart("parent_dir", new StringBody(parentFilePath, ContentType.create("text/plain", Consts.UTF_8)));
                multipartEntityBuilder.addTextBody("filename", new File(breakpointUploadTask.getFileServerPath()).getName());
                
                HttpEntity requesEntity = multipartEntityBuilder.build();
                System.out.println(requesEntity.getContentEncoding());
                System.out.println(requesEntity.getContentType());
                httpPost.setEntity(requesEntity); 
                response = httpclient.execute(httpPost);
                System.out.println(response.getStatusLine());
                int statusCode = response.getStatusLine().getStatusCode();
                HttpEntity responseEntity = response.getEntity();
                String responseContent = MyHttpClientUtils.getResponseString(responseEntity);
                System.out.println("上传返回的信息: " + responseContent);
                EntityUtils.consume(responseEntity);
                if(statusCode != 200) {
                    throw new KumaoException("上传文件失败");
                }
            } catch (Exception e) {
                //e.printStackTrace();
                throw e;
            } finally {
                if(response != null) {
                    response.close();
                }
                if(httpclient != null) {
                    httpclient.close();
                }
            }
            
        } catch (Exception e) {
            //e.printStackTrace();
            throw e;
        } 
    }
    
    //获取上传链接
    private static String getUploadUrl(String url, String token) throws Exception {
        String responseContent = null;  
        CloseableHttpClient httpclient = HttpClients.createDefault();  
        CloseableHttpResponse response = null;
        String uploadUrl = null;
        try {
            HttpGet httpGet = new HttpGet(url); 
            httpGet.addHeader("Authorization", "Token " + token);
            httpGet.addHeader("Accept", "application/json; charset=utf-8; indent=4");
            response = httpclient.execute(httpGet);
            System.out.println(response.getStatusLine());
            int statusCode = response.getStatusLine().getStatusCode();
            if(statusCode != 200) {
                System.out.println("获取上传链接失败");
                throw new KumaoException("获取上传链接失败");
            }
            HttpEntity entity = response.getEntity();
            responseContent = MyHttpClientUtils.getResponseString(entity);
            System.out.println("debug:" + responseContent);  
            EntityUtils.consume(entity);  
            //处理一下字符串
            uploadUrl = responseContent.substring(1, responseContent.length() - 1);
        } catch (Exception e) {
            //e.printStackTrace();
            throw e;
        } finally {
            if(response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                }
            }
            if(httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                }  
            }
        }
        return uploadUrl;
    }
    
    //获取库id
    private static String getLibraryId(String path) {
        String[] arr = path.split("/");
        return arr[1];
    }

    //获取文件路径
    private static String getFilePath(String path) {
        String filePath = "/";
        String[] arr = path.split("/");
        if(arr.length >= 2) {
            for(int i = 2; i < arr.length; i++) {
                if(i == arr.length - 1) {
                    filePath += arr[i];
                } else {
                    filePath += arr[i] + "/";
                }
            }
        }
        return filePath;
    }
}
